/* util设计一些帮助函数
 */
package illusion

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/go-redis/redis"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

type env struct {
	sync.Mutex
	mapEnv map[string]string
}

var _env *env
var theOnce sync.Once

func getEnv() *env {
	theOnce.Do(func() {
		_env = &env{
			mapEnv: make(map[string]string),
		}
		setEnv(_env)
	})
	return _env
}

func (e *env) Get(key string) string {
	e.Lock()
	v := e.mapEnv[key]
	e.Unlock()
	return v
}

func (e *env) Set(key string, value string) {
	e.Lock()
	e.mapEnv[key] = value
	e.Unlock()
}

func setEnv(envS *env) {
	//envS := getEnv()
	currentPath,err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(".env路径:" + currentPath + string(filepath.Separator) + ".env")
	env, err := os.Open(currentPath + string(filepath.Separator) + ".env")
	defer env.Close()
	if err != nil {
		panic(err.Error())
	}
	buff := bufio.NewReader(env)
	for {
		ByteLine, _, err := buff.ReadLine()
		line := string(ByteLine[:])
		if line == "" { //空行，过滤
			if io.EOF == err {
				break
			}
			continue
		}
		if strings.Contains(line, "#") { //过滤#
			continue
		}
		//Logger().Println("获取到配置行：" + line)
		if is_debug {
			fmt.Println("获取到配置行：" + line)
		}
		v := strings.Split(line, "=")
		/*if len(v) == 1 { //应该是这个理
			envS.Lock()
			envS._env[key] = notFound
			envS.Unlock()
			continue
		}*/
		if len(v) != 2 {
			panic(".env配置参数格式错误")
		}
		//Logger().Println("%v", v)
		envKey := strings.TrimSpace(v[0])
		envValue := strings.TrimSpace(v[1])
		if envKey == "" {
			panic("配置里有键值为空")
		}
		//if envValue == "" {
		//envS.Lock()
		//	envS.Set(envKey, envValue)
		//envS.mapEnv[envKey] = envValue
		//envS.Unlock()
		//	continue
		//}
		///Logger().Println("获取到key:'" + envKey + "', value:'" + envValue+ "'")
		if is_debug {
			fmt.Println("获取到key:'" + envKey + "', value:'" + envValue + "'")
		}
		//envS.Lock()
		//envS.mapEnv[envKey] = envValue
		//envS.Unlock()
		envS.Set(envKey, envValue)
		if err != nil || io.EOF == err {
			//Logger().Println("配置文件已到结尾")
			if is_debug {
				fmt.Println("配置文件已到结尾")
			}
			break
		}
	}
}

func valueOfEnv(key string, NoFound string) string {
	env := getEnv()
	val := env.Get(key)
	if val == "" {
		return NoFound
	}
	return val
}

func EnvInt(key string, notFound int) int {
	notFoundSr := strconv.Itoa(notFound)
	val := valueOfEnv(key, notFoundSr)
	if val == "" {
		return notFound
	}
	v, err := strconv.Atoi(val)
	if err != nil {
		panic(err.Error())
	}
	return v
}

//支持1,t,T,TRUE, True, true,反之亦然
func EnvBool(key string, notFound bool) bool {
	notFoundS := ""
	if notFound {
		notFoundS = "true"
	} else {
		notFoundS = "false"
	}
	val := valueOfEnv(key, notFoundS)
	v, err := strconv.ParseBool(val)
	if err != nil {
		panic(err.Error())
	}
	return v
}

func EnvString(key string, notFound string) string {
	return valueOfEnv(key, notFound)
}

type sqlOption struct {
	Driver   string
	User     string
	Password string
	Host     string
	Port     string
	Database string
}

func dbConfig() *sqlOption {
	config := &sqlOption{}
	driver := EnvString(DatabaseDriver, "")
	config.Driver = driver
	user := EnvString(DatabaseUser, "")
	config.User = user
	pwd := EnvString(DatabasePassword, "")
	config.Password = pwd
	host := EnvString(DatabaseHost, "")
	config.Host = host
	port := EnvString(DatabasePort, "-1")
	config.Port = port
	database := EnvString(DatabaseName, "")
	config.Database = database
	if driver == "" || user == "" || host == "" || port == "-1" || database == "" { //密码可以为空
		panic("数据库参数配置不明")
	}
	return config
}

/*  关于文件的一些uil */
func absPath(relative string) string {
	basePath := string(filepath.Separator) + strings.TrimPrefix(relative, "/")
	currentPath, err := filepath.Abs(".") //当前路径
	if err != nil {
		logging("后去绝对路径时出错:" + err.Error())
		os.Exit(0)
	}
	fullPath := currentPath + basePath + string(filepath.Separator)
	return fullPath
}

func pathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

/*  文件util结束 */

/* session相关的util   */
func baseSessionDirectory() (string, error) {
	session := EnvString(SessionName, "")
	if session != "file" {
		Logger().Println("getSessionFile只针对file")
		if is_debug {
			fmt.Println("getSessionFile只针对file")
		}
		os.Exit(0)
	}
	path := EnvString(SessionPath, "")
	if path == "" {
		logging("使用file作为session存储方式时,未给出session存储路径")
		os.Exit(0)
	}
	fullPath := absPath(path)
	if pathExists(fullPath) {
		return fullPath, nil
	} else {
		return "", errors.New("session存储目录不存在")
	}
}
func sessionFile(sid string) (*os.File, error) {
	directory, err := baseSessionDirectory()
	if err != nil {
		logging("session存储目录不存在，退出...")
		os.Exit(0)
	}
	path := directory + sid
	if file, err := os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
		return nil, err
	} else {
		return file, nil
	}
}

//获取一个连接
func redisClient() *redis.Client {
	session := EnvString(SessionName, "")
	if session != "redis" {
		panic("session未使用redis作为存储")
	}
	sessionHost := EnvString(SessionRedisHost, "")
	sessionPort := EnvString(SessionRedisPort, "")
	if sessionHost == "" || sessionPort == ""{
		panic("未找到redis相关选项")
	}
	return redis.NewClient(&redis.Options{
		Addr: sessionHost+":" + sessionPort,
		DB:   0,
	})
}

/* session util 结束 */

/*  logger的一些简化操作 */
func logging(v interface{}) {
	Logger().Println(v)
	if is_debug {
		fmt.Println(v)
	}
}

/** Cache util **/
func cacheRedisClient() *redis.Client{
	host := EnvString(CacheRedisHost, "")
	port := EnvString(CacheRedisPort, "")
	if host == "" || port == "" {
		logging("设置缓存时redis host或者port未空")
		panic("设置缓存时redis host或者port未空")
	}
	return redis.NewClient(&redis.Options{
		Addr: host+":" + port,
		DB:   1,
	})
}
